package com.itheima.auth.config;

import com.itheima.auth.intergration.exception.WebResponseExceptionTranslator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.token.TokenService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

/**
 * 认证服务器配置类
 */
@Configuration
@EnableAuthorizationServer //开启认证服务
public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * ClientDetailsServiceConfigurer**:用来配置客户端详情服务（ClientDetailsService），
     * 客户端详情信息在 这里进行初始化，你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息，
     * 支持的认证方式，如果采用授权码重定向地址
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //在内存中定义客户端详情
        clients.inMemory()
                .withClient("app_client").secret(passwordEncoder.encode("app_secret"))
                .scopes("all").authorizedGrantTypes("authorization_code", "refresh_token", "password").autoApprove(false).redirectUris("http://www.itcast.cn")
                .and()
                .withClient("pc_client").secret(passwordEncoder.encode("pc_secret"))
                .scopes("all").authorizedGrantTypes("authorization_code", "refresh_token", "password").autoApprove(false).redirectUris("http://www.itcast.cn");
    }


    @Autowired
    private TokenStore tokenStore;


    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;


    /**
     * AuthorizationServerEndpointsConfigurer**:用来配置授权（authorization）以及令牌（token）的访问端点和令牌服务(token services)
     * 配置令牌有效时间 默认12个小时
     */
    @Bean
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore);
        tokenServices.setTokenEnhancer(jwtAccessTokenConverter);
        tokenServices.setRefreshTokenValiditySeconds(250000);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setAccessTokenValiditySeconds(80000);  //token失效时间
        return tokenServices;
    }


    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private WebResponseExceptionTranslator webResponseExceptionTranslator;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager)
                .tokenServices(tokenService()) //令牌服务 指定令牌有效期等配置
                .exceptionTranslator(webResponseExceptionTranslator)
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }



    /**
     * **令牌端点的安全约束**
     * @param security
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.tokenKeyAccess("permitAll()") //tokenkey这个endpoint当使用JwtToken且使用非对称加密时，资源服务用于获取公钥而开放的，这里指这个 endpoint完全公开。
                .checkTokenAccess("permitAll()")  //checkToken这个endpoint完全公开
                .allowFormAuthenticationForClients(); //允许表单认证(密码/授权码模式认证)
    }
}
